/**
 * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "GPUImageMonochromeFilter.h"
#include "types.h"

const std::string GPUImageMonochromeFilter::MONOCHROME_FRAGMENT_SHADER = R"(
    #extension GL_OES_EGL_image_external : require
    precision lowp float;

    varying highp vec2 textureCoordinate;

    uniform samplerExternalOES inputImageTexture;
    uniform float intensity;
    uniform vec3 filterColor;

    const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);

    void main()
    {
        // desat, then apply overlay blend
        lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
        float luminance = dot(textureColor.rgb, luminanceWeighting);

        lowp vec4 desat = vec4(vec3(luminance), 1.0);

        // overlay
        lowp vec4 outputColor = vec4(
            (desat.r < 0.5 ? (2.0 * desat.r * filterColor.r) : (1.0 - 2.0 * (1.0 - desat.r) * (1.0 - filterColor.r))),
            (desat.g < 0.5 ? (2.0 * desat.g * filterColor.g) : (1.0 - 2.0 * (1.0 - desat.g) * (1.0 - filterColor.g))),
            (desat.b < 0.5 ? (2.0 * desat.b * filterColor.b) : (1.0 - 2.0 * (1.0 - desat.b) * (1.0 - filterColor.b))),
            1.0
        );

        // which is better, or are they equal?
        gl_FragColor = vec4(mix(textureColor.rgb, outputColor.rgb, intensity), textureColor.a);
    }
)";

GPUImageMonochromeFilter::GPUImageMonochromeFilter()
    : intensity(1.0f), color(new float[]{0.6f, 0.45f, 0.3f, 1.0f}) {}

GPUImageMonochromeFilter::GPUImageMonochromeFilter(const float intensityVal,
                                                   float *colorArray)
    : GPUImageFilter(NO_FILTER_VERTEX_SHADER, MONOCHROME_FRAGMENT_SHADER)
{
    intensity = intensityVal;
    color = colorArray;
}

GPUImageMonochromeFilter::~GPUImageMonochromeFilter() { delete[] color; }

void GPUImageMonochromeFilter::onInit()
{
    GPUImageFilter::onInit();
    intensityLocation = glGetUniformLocation(getProgram(), "intensity");
    filterColorLocation = glGetUniformLocation(getProgram(), "filterColor");
}

void GPUImageMonochromeFilter::onInitialized()
{
    GPUImageFilter::onInitialized();
    setIntensity(1.0f);
    setColor(new float[]{0.6f, 0.45f, 0.3f, 1.f});
}

void GPUImageMonochromeFilter::setIntensity(const float intensityVal)
{
    intensity = intensityVal;
    setFloat(intensityLocation, intensity);
}

void GPUImageMonochromeFilter::setColor(float *colorArray)
{
    color = colorArray;
    setColor(color[RGBA::R], color[RGBA::G], color[RGBA::B]);
}

void GPUImageMonochromeFilter::setColor(float red, float green, float blue)
{
    setFloatVec3(filterColorLocation, new float[]{red, green, blue});
}